use crate::db;
use crate::ffmpeg::FfmpegController;
use crate::global;
use core_api::checksum;
use std::collections::HashSet;
use std::ffi::OsString;
use std::path::Path;
use sysinfo::{Pid, ProcessesToUpdate, System};
use tauri::{command, AppHandle, Runtime, Window};

type Result<T> = std::result::Result<T, String>;

fn test_ffmpeg() {
    //1222
    //use bwexam_lib::ffmpeg::FfmpegController;
    let args = vec![
    "ffmpeg".to_string(),
    "-hide_banner".to_string(),
    "-y".to_string(),
    "-f".to_string(),
    "gdigrab".to_string(),
    "-i".to_string(),
    "desktop".to_string(),
    "-r".to_string(),
    "10".to_string(),
    "-t".to_string(),
    "28800".to_string(),
    "-b:v".to_string(),
    "550k".to_string(),
    "-vf".to_string(),
    "\"scale=1024:-1,drawtext=fontfile=msyh.ttf:text='薛1 %{localtime}':fontsize=12:fontcolor=red:x=1:y=1,drawtext=fontfile=msyh.ttf:text='%{localtime}':x=mod(100*t\\,w):y=abs(sin(t))*h*0.9:box=0:fontcolor=gray@0.4\"".to_string(),
    "test4.mkv".to_string(),
];

    let mut fc = FfmpegController::new();
    let log_rx = fc.run_async(args);

    let log_thread = std::thread::spawn(move || {
        for line in log_rx {
            println!("[Async Log] {}", line);
        }
        println!("Log thread exiting");
    });

    std::thread::sleep(std::time::Duration::from_secs(20));

    // 等待ffmpeg 退出
    fc.wait_stop();
    // 等待日志线程退出
    let _ = log_thread.join();
    println!("=== Async FFmpeg Stopped ===");
}


#[command]
pub async fn start_recording<R: Runtime>(
    app: AppHandle<R>,
    window: Window<R>,
    output_file: &Path,
    watermark_text: String,
    force_open_camera: bool, // has_callback: bool,
                             // record_status_channel: Channel<String>,
) -> Result<u32> {
   //  test_ffmpeg() ;
    let pid = 0;
    if global::read().is_recording() {
        return Ok(pid);
    }
    // 确保上级目录存在
    if let Some(dest_path) = output_file.parent() {
        let _ = std::fs::create_dir_all(dest_path);
    }

    // 保存到全局状态
    global::write().set_output_file(output_file.to_path_buf());
    let outfile = output_file.to_str().unwrap(); //global::read().get_save_path_name();
                                                 // 优化参数 https://ask.csdn.net/questions/8072127
    
    
    let is_open_camera;
    let args = match detect_camara_mic(&app, &window) {
        // 有摄像头和麦克风
        (Some(camara), Some(mic)) => {
            is_open_camera = true;
            // ffmpeg -y -probesize 10M -f gdigrab -r 10 -t 28800 -i desktop -f dshow -i video="RGB Camera" -f dshow -i audio="外部麦克风 (Realtek(R) Audio)" -filter_complex "[0]scale=1024:-1[desktop]; [1]scale=160:120[cam]; [desktop][cam]overlay=5:5,drawtext=text='%{localtime}':x=5:y=5:fontsize=12:fontcolor=red,drawtext=text='%{localtime}':x=mod(100*t\,w):y=abs(sin(t))*h*0.9:box=0:fontcolor=gray@0.4[video]; [2]anull[audio]"  -map "[video]" -map "[audio]" -b:v 550k -c:v libx264 -c:a aac all.mp4
            vec![
                 "ffmpeg".to_string(),
    "-hide_banner".to_string(),
    "-y".to_string(),
    "-probesize".to_string(), "10M".to_string(),
    "-f".to_string(),
    "gdigrab".to_string(),
    "-r".to_string(),
    "10".to_string(),
    "-t".to_string(),
    "28800".to_string(),
    "-i".to_string(),
    "desktop".to_string(),
    "-f".to_string(), "dshow".to_string(), "-i".to_string(), format!("video={}", camara),
    "-f".to_string(), "dshow".to_string(), "-i".to_string(), format!("audio={}", mic),
    "-filter_complex".to_string(),
    format!("[0]scale=1024:-1[desktop];[1]scale=160:-1 [cam]; [desktop][cam]overlay=5:5,drawtext=fontfile=msyh.ttf:text='{} %{{localtime}}':x=5:y=5:fontsize=12:fontcolor=red,drawtext=fontfile=msyh.ttf:text='%{{localtime}}':x=mod(100*t\\,w):y=abs(sin(t))*h*0.9:box=0:fontcolor=gray@0.4[video]; [2]anull[audio]", watermark_text),
    "-map".to_string(), "[video]".to_string(), "-map".to_string(), "[audio]".to_string(),
    "-b:v".to_string(), "550k".to_string(),
    "-c:v".to_string(), "libx264".to_string(), "-c:a".to_string(), "aac".to_string(),
    outfile.to_string(),
    // 输出摄像头截图,不需要截图可以注掉一下2行
    //"-map".to_string(), "1".to_string(), "-f".to_string(), "image2".to_string(), "-vf".to_string(), format!("fps={}", 1).as_str(),
    //"-update".to_string(), "1".to_string(), "tempc".to_string()
]
        }
        // 有摄像头和 无麦克风
        (Some(camara), None) => {
            is_open_camera = true;
            //ffmpeg -y -probesize 100M -f gdigrab -r 10 -i desktop -f dshow -i video="FULL HD 1080P Webcam" -filter_complex "[0]scale=1024:-1[desktop];[1]scale=160:120[cam];[desktop][cam]overlay=5:5,drawtext=text='%{localtime}':x=5:y=5:fontsize=12:fontcolor=red,drawtext=text='%{localtime}':x=mod(100*t\,w):y=abs(sin(t))*h*0.9:box=0:fontcolor=gray@0.4" -b:v 550k -c:v libx264 all.mp4
            vec![
                 "ffmpeg".to_string(),
    "-hide_banner".to_string(),
    "-y".to_string(),
    "-probesize".to_string(), "10M".to_string(),
    "-f".to_string(),
    "gdigrab".to_string(),
    "-r".to_string(),
    "10".to_string(),
    "-t".to_string(),
    "28800".to_string(),
    "-i".to_string(),
    "desktop".to_string(),
    "-f".to_string(), "dshow".to_string(), "-i".to_string(), format!("video={}", camara),
    "-filter_complex".to_string(),
    format!("[0]scale=1024:-1[desktop];[1]scale=160:-1 [cam]; [desktop][cam]overlay=5:5,drawtext=fontfile=msyh.ttf:text='{} %{{localtime}}':x=5:y=5:fontsize=12:fontcolor=red,drawtext=fontfile=msyh.ttf:text='%{{localtime}}':x=mod(100*t\\,w):y=abs(sin(t))*h*0.9:box=0:fontcolor=gray@0.4", watermark_text),
    "-b:v".to_string(), "550k".to_string(),
    "-c:v".to_string(), "libx264".to_string(), "-c:a".to_string(), "aac".to_string(),
    outfile.to_string(),
    // 输出摄像头截图,不需要截图可以注掉一下2行
    //"-map".to_string(), "1".to_string(), "-f".to_string(), "image2".to_string(), "-vf".to_string(), format!("fps={}", 1),
    //"-update".to_string(), "1".to_string(), "tempc".to_string()
]
        }
        // 无摄像头和 有麦克风
        (None, Some(mic)) => {
            is_open_camera = false;
            //ffmpeg -y -probesize 100M -f gdigrab -r 10 -i desktop -f dshow -i audio="外部麦克风 (Realtek(R) Audio)" -filter_complex "[0]scale=1024:-1[desktop];[desktop]drawtext=text='%{localtime}':x=5:y=5:fontsize=12:fontcolor=red,drawtext=text='%{localtime}':x=mod(100*t\,w):y=abs(sin(t))*h*0.9:box=0:fontcolor=gray@0.4[video];[1]anull[audio]" -map "[video]" -map "[audio]" -b:v 550k -c:v libx264 -c:a aac all.mp4
            vec![
                 "ffmpeg".to_string(),
    "-hide_banner".to_string(),
    "-y".to_string(),
    "-probesize".to_string(), "10M".to_string(),
    "-f".to_string(),
    "gdigrab".to_string(),
    "-r".to_string(),
    "10".to_string(),
    "-t".to_string(),
    "28800".to_string(),

    // "-fs".to_string(), "4096M".to_string(),

    "-i".to_string(),
    "desktop".to_string(),
    "-f".to_string(), "dshow".to_string(), "-i".to_string(), format!("audio={}", mic),
    "-filter_complex".to_string(),
    format!("[0]scale=1024:-1[desktop];[desktop]drawtext=fontfile=msyh.ttf:text='{} %{{localtime}}':x=5:y=5:fontsize=12:fontcolor=red,drawtext=fontfile=msyh.ttf:text='%{{localtime}}':x=mod(100*t\\,w):y=abs(sin(t))*h*0.9:box=0:fontcolor=gray@0.4[video]; [1]anull[audio]", watermark_text),
    "-map".to_string(), "[video]".to_string(), "-map".to_string(), "[audio]".to_string(),
    "-b:v".to_string(), "550k".to_string(),
    "-c:v".to_string(), "libx264".to_string(), "-c:a".to_string(), "aac".to_string(),
    outfile.to_string()
]
        }
        // 无摄像头和无麦克风
        _ => {
            is_open_camera = false;
            vec![
                 "ffmpeg".to_string(),
    "-hide_banner".to_string(),
    "-y".to_string(),
    "-f".to_string(),
    "gdigrab".to_string(),
    "-i".to_string(),
    "desktop".to_string(),
    "-r".to_string(),
    "10".to_string(),
    "-t".to_string(),
    "28800".to_string(),
    // "-fs".to_string(), "4096M".to_string(),
    "-b:v".to_string(),
    "550k".to_string(),
    "-vf".to_string(),
    format!("\"scale=1024:-1,drawtext=fontfile=msyh.ttf:text='{} %{{localtime}}':fontsize=12:fontcolor=red:x=1:y=1,drawtext=fontfile=msyh.ttf:text='%{{localtime}}':x=mod(100*t\\,w):y=abs(sin(t))*h*0.9:box=0:fontcolor=gray@0.4\"", watermark_text),
    outfile.to_string(),
]
        }
    };
    if force_open_camera && !is_open_camera {
        return Err("无法开启摄像头!".to_string());
    }

   test_ffmpeg() ;


    /*

    let mut fc = FfmpegController::new();
    let log_rx = fc.run_async(args);
    let log_thread = std::thread::spawn(move || {
        let mut n = 1;
        let mut is_first = true;
        for line in log_rx {
            println!("{}", &line);
            // 输出的信息格式
            //frame=    0 fps=0.0 q=0.0  size=       0KiB time=N/A bitrate=N/A dup=0 drop=116 speed=N/A
            //frame=    5 fps=0.7 q=26.0 size=       0KiB time=00:00:00.30 bitrate=   1.3kbits/s dup=0 drop=125 speed=0.0448x
            if n % 2 == 0 {
                if line.starts_with("frame=") {
                    let p1 = line.find("time=");
                    let p2 = line.find("bitrate=");
                    if let (Some(start), Some(end)) = (p1, p2) {
                        let time_str = &line[start + "time=".len()..end - 4];
                        if !time_str.starts_with("N/A") {
                            if is_first {
                                //let _ = app.emit(EVENT_START_RECORDING, "START");
                                db::send_msg(db::Message::new(
                                    db::MsgFlag::RECORDING,
                                    db::MsgStatus::START,
                                    format!("{}", pid),
                                    String::default(),
                                ));
                                is_first = false;
                            }
                           

                            db::send_msg(db::Message::new(
                                db::MsgFlag::RECORDING,
                                db::MsgStatus::PROGRESS,
                                format!("{}", pid),
                                time_str.to_string(),
                            ));
                        }
                    }
                }
            }
            n += 1;
        }
        println!("Log thread exiting");
    });
    
    std::thread::sleep(std::time::Duration::from_secs(20));
    // 等待ffmpeg 退出
    fc.wait_stop();
    // 等待日志线程退出
    let _ = log_thread.join();
    println!("=== Async FFmpeg Stopped ===");
    //global::write().set_ffmpeg(Some(fc));
    */


    

    Ok(pid)
}

/// 探测摄像头和麦克风
fn detect_camara_mic<R: Runtime>(
    _app: &AppHandle<R>,
    _window: &Window<R>,
) -> (Option<String>, Option<String>) {
    let mut camara: Option<String> = None;
    let mut mic: Option<String> = None;

    // 探测 摄像头和 麦克风
    let args = vec![
        "ffmpeg".to_string(),
        "-list_devices".to_string(),
        "true".to_string(),
        "-f".to_string(),
        "dshow".to_string(),
        "-i".to_string(),
        "dummy".to_string(),
    ];
    let mut fc = FfmpegController::new();
    fc.run_sync(args);
    let logs = fc.get_logs();
    drop(fc);

    //const START_STR: &str = r#"] ""#; //ffmpeg7.0 中间有1个空格
    const START_STR: &str = r#"]  ""#; //ffmpeg4.4 中间有2个空格
    const END_STR: &str = r#"""#;
    //ffmpeg4.4 返回结果为1
    // [dshow @ 000001f3b006f9c0] "Integrated Camera" (video)
    // [dshow @ 000001f3b006f9c0] "外部麦克风 (Realtek(R) Audio)" (audio)
    let device_list = logs
        .iter()
        //.inspect(|line| println!("==>{}", line)) //输出调试
        .filter(|line| {
            let ok = line.starts_with("[dshow")
                && ((line.ends_with("(video)") || line.ends_with("(audio)")) // ffmpeg7.0
                            || (line.to_lowercase().contains("cam") || line.contains("麦克"))); // ffmpeg4.4

            ok
        })
        .map(|line| {
            if let Some(start) = line.find(START_STR) {
                return Some(&line[start + START_STR.len()..]);
            }
            None
        })
        .filter(|line| line.is_some())
        .map(|line| line.unwrap())
        .inspect(|line| println!("==>{}", line)) //输出调试
        .collect::<Vec<&str>>();
    // 输出
    //Integrated Camera" (video)
    //外部麦克风 (Realtek(R) Audio)" (audio)
    //麦克风阵列 (Realtek(R) Audio)" (audio)

    // 获取可用的麦克

    for device in &device_list {
        if device.ends_with("(audio)") || device.contains("麦克") {
            let end = device.find(END_STR).unwrap();
            let device_name = &device[..end];

            let audio_args = vec![
                "ffmpeg".to_string(),
                "-y".to_string(),
                "-loglevel".to_string(),
                "quiet".to_string(),
                "-f".to_string(),
                "dshow".to_string(),
                "-i".to_string(),
                format!("audio={}", device_name),
                // r#"audio=外部麦克风 (Realtek(R) Audio)"#, //这里不用加双引号
                "-aframes".to_string(),
                "1".to_string(),
                "testmic.aac".to_string(),
            ];

            let mut audio_fc = FfmpegController::new();
            let r = audio_fc.run_sync(audio_args);

            // println!("{}  {:?},{}",device_name,output.status,output.stderr);
            println!("AUDIO:[{}], result: {}", device_name, r);
            if r == 0 {
                //return Some(device_name);
                mic = Some(device_name.to_string());
                break;
            }
        }
    }

    // 获取可用的摄像头
    // ffmpeg -f dshow -i video="FULL HD 1080P Webcam" -vframes 1 screenshot.png

    for device in &device_list {
        if (device.ends_with("(video)") || device.to_lowercase().contains("cam"))
            && !device.contains("screen")
        {
            let end = device.find(END_STR).unwrap();
            let device_name = &device[..end];

            let video_args = vec![
                "ffmpeg".to_string(),
                "-y".to_string(),
                "-loglevel".to_string(),
                "quiet".to_string(),
                "-f".to_string(),
                "dshow".to_string(),
                "-i".to_string(),
                format!("video={}", device_name),
                "-vframes".to_string(),
                "1".to_string(),
                "testcamara.png".to_string(),
            ];
            let mut video_fc = FfmpegController::new();
            let r = video_fc.run_sync(video_args);

            println!("VIDEO:[{}], result: {}", device_name, r);
            if r == 0 {
                camara = Some(device_name.to_string());
                break;
            }
        }
    }
    println!("camara: {:?} , mic:{:?}", &camara, &mic);
    (camara, mic)
}

#[command]
pub fn stop_recording() -> Result<Option<String>> {
    if global::write().stop_ffmpeg() == 0 {
        db::send_msg(db::Message::new(
            db::MsgFlag::RECORDING,
            db::MsgStatus::SUCCESS,
            format!("{}", 0),
            String::default(),
        ));
        //此处已经保证进程已经关闭
        if let Some(outfile) = global::read().get_output_file() {
            // todo:这里可以调用ffmpeg 写入元信息
            return Ok(checksum::generate_checksum(outfile.to_str().unwrap()));
        }
    }
    Err("关闭录屏失败!".to_string())
}

pub fn kill_process(pid: u32) -> bool {
    let mut system = System::new_all();
    system.refresh_processes(ProcessesToUpdate::Some(&[Pid::from_u32(pid)]), true); // 更新进程信息

    if let Some(process) = system.process(Pid::from_u32(pid)) {
        println!("find: {} - {:?}", pid, process.name());
        process.kill(); // 默认等价于 SIGTERM（Windows 是 TerminateProcess）
        true
    } else {
        println!("can not find PID: {}", pid);
        false
    }
}

pub fn kill_process_by_names(target_names: Vec<String>) -> Vec<(OsString, u8)> {
    let mut result: Vec<(OsString, u8)> = vec![]; // 存储返回结果
    let name_set: HashSet<OsString> = target_names
        .iter()
        .map(|s| OsString::from(s.to_ascii_lowercase())) // 转小写进行匹配
        .collect();

    let mut system = System::new(); // 不加载全部信息
    system.refresh_processes(ProcessesToUpdate::All, true);
    for (pid, process) in system.processes() {
        let name = process.name().to_ascii_lowercase(); // 获取进程名并转为小写
                                                        //println!("进程===========: {:?} ", process.name());
        if name_set.contains(&name) {
            // 尝试终止进程
            let killed = if process.kill() {
                println!("success kill  {:?} [PID: {}]", process.name(), pid);
                1 // 成功杀死进程，返回 1
            } else {
                println!("can not kill  {:?} [PID: {}]", process.name(), pid);
                0 // 无法杀死进程，返回 0
            };
            result.push((process.name().to_os_string(), killed));
        }
    }

    result
}

/// 获取当前所有进程的名称（可能包含重复）
pub fn get_all_process() -> Vec<String> {
    let mut system = System::new();
    system.refresh_processes(ProcessesToUpdate::All, true); // 仅刷新进程列表

    system
        .processes()
        .values()
        .map(|proc| proc.name().to_string_lossy().to_string())
        .collect()
}

pub fn check_process(target_names: Vec<String>) -> Vec<(String, u8)> {
    let mut system = System::new();
    system.refresh_processes(ProcessesToUpdate::All, true);

    // 收集当前正在运行的进程名（统一小写）
    let running_processes: HashSet<OsString> = system
        .processes()
        .values()
        .map(|p| p.name().to_ascii_lowercase())
        .collect();

    // 遍历目标进程名，判断是否存在
    target_names
        .iter()
        .map(|name| {
            let lower = OsString::from(name.to_ascii_lowercase());
            let exists = if running_processes.contains(&lower) {
                1
            } else {
                0
            };
            (name.clone(), exists)
        })
        .collect()
}

#[command]
pub async fn validate_checksum<R: Runtime>(
    _app: AppHandle<R>,
    output_file: &Path,
) -> Result<String> {
    checksum::validate_checksum(output_file.to_str().unwrap())
}
